/**
 * @Author: 陈瑞鹏
 * @Date:   2021-11-08 19:19:24
 * @Last Modified by:   陈瑞鹏
 * @Last Modified time: 2025-01-20 11:39:50
 */

import * as pako from "pako";
import * as io from "socket.io-client";
import GameData from '../GameData';
import { HttpConfig } from '../NetManager';
import ReportLogs from "../ReportLogs";
// import { io } from './socket.io.1.4.8.js';

export default class SocketManager {

    private static _ins: SocketManager = null;
    private readonly MAX_RECONNECT_ATTEMPTS = 5;
    private readonly RECONNECT_INTERVAL = 3000; // 3秒
    private reconnectAttempts = 0;
    private reconnectTimer: any = null;

    public static get ins() {

        if (this._ins == null) {

            this._ins = new SocketManager();
        }

        return this._ins;
    }

    public socket: any = null;

    public isReConnect: boolean = false; //是否重连操作

    private isConnecting: boolean = false;

    public jiemi(cb, data) {

        let t = new Promise((resolve, reject) => {
            this.ab2str(data, (e) => {
                // resolve(e);
                cb(e);
            })
        })
    }

    public ab2str(u, f) {

        var b = new Blob([u]);
        var r = new FileReader();
        r.readAsText(b, 'utf-8');
        r.onload = function () {
            if (f) f.call(null, r.result)
        }
    }

    public initSocket() {

        if (this.socket) return;

        let url = HttpConfig.SOCKET_NAME;

        if (CC_DEBUG) {
            // url = "ws://test.tuanjian.game4.cn/shuchaopiao"
            // url = "ws://127.0.0.1:3000/shuchaopiao"
            url = "ws://127.0.0.1:3000/shuchaopiao"
        }

        console.log("url:", url)

        this.socket = io.connect(url, {
            transports: ['websocket'], // 使用WebSocket协议，提供全双工通信
            // reconnection: true // 启用断线重连，保证游戏体验
        });

        let self = this;

        // 设置事件监听
        this.setupEventListeners();
    }

    private setupEventListeners() {
        if (!this.socket) return;

        // 连接成功
        this.socket.on('connect', () => {
            console.log("链接成功", this.socket.id);
            this.resetReconnectState();

            if (this.isReConnect) {
                this.isReConnect = false;
                //上报日志
                // ReportLogs.ins.behaviorReporting("房间操作", "重连后，重新进入房间操作", GameData.ins.gameState.roomId);

                this.socket.emit('join-room', {
                    roomId: GameData.ins.gameState.roomId,
                    userId: GameData.ins.username,
                    avatar: GameData.ins.avatar,
                    nickName: GameData.ins.nickName,
                });
            }
        });

        // 断开连接
        this.socket.on("disconnect", () => {
            console.log("连接断开，准备重连");
            GameData.ins.list = [];
            GameData.ins.mainNode.emit("onLeaveRoom");
            this.isReConnect = true;
            this.handleReconnect();
        });

        // 连接失败
        this.socket.on('connect_failed', () => {
            console.log('连接失败，准备重连');
            this.isReConnect = true;
            this.handleReconnect();
        });

        // 连接错误
        this.socket.on('connect_error', () => {
            console.error('连接错误');
            this.handleReconnect();
        });

        // 创建房间事件
        this.socket.on("room-created", (e) => {
            this.handleSocketEvent("创建房间1", e, (data) => {

                console.log("监听创建房间", data);
                // GameData.ins.gameState.players = data.gameState.players;
                GameData.ins.gameState.roomId = data.roomInfo.roomId;
                GameData.ins.gameState.ownerId = data.roomInfo.ownerId;

                GameData.ins.getRoomUserData(1, Number(GameData.ins.pageInfo.pageSize), "lastActive", "desc", GameData.ins.username);
                GameData.ins.mainNode.emit("onJoinRoom");
                GameData.ins.mainNode.emit("onRoomDataChange");

                //上报日志
                ReportLogs.ins.behaviorReporting("房间操作", "创建房间成功", GameData.ins.gameState.roomId);
                // if (data.roomId != GameData.ins.roomId) {
                //     GameData.ins.list = [];
                // }
                // //标记房主
                // GameData.ins.roomOwnerId = data.ownerId;
                // // GameData.ins.list = data.roomUsers;
                // GameData.ins.roomId = data.roomId;
                // // GameData.ins.mainNode.emit("onRoomDataChange");
                // GameData.ins.getRoomUserData("1");
            });
        });

        // 退出房间事件
        this.socket.on("player-left", (e) => {
            this.handleSocketEvent("退出房间", e, (data) => {
                console.log("退出房间");

                GameData.ins.getRoomUserData(GameData.ins.pageInfo.page, Number(GameData.ins.pageInfo.pageSize), "lastActive", "desc", GameData.ins.username);

                // GameData.ins.gameState.roomId = null;
                // GameData.ins.gameState.ownerId = null;
                // GameData.ins.gameState = data.gameState;
                // let arr = [];
                // for (let i in roomUsers) {
                //     if (roomUsers[i] && !roomUsers[i].isExit) {
                //         arr.push(roomUsers[i]);
                //     }
                // }
                // // GameData.ins.list = arr;
                // GameData.ins.gameState.roomId = data.gameState.roomId;
                GameData.ins.mainNode.emit("onRoomDataChange");
                // GameData.ins.getRoomUserData(GameData.ins.pageInfo.page || "1");
            });
        });

        // 开始游戏事件
        this.socket.on("game-start", (e) => {
            this.handleSocketEvent("开始游戏", e, (data) => {
                console.log("开始游戏", data);
                // 重置游戏状态
                GameData.ins.isOver2 = false;
                GameData.ins.isOver = false;
                GameData.ins.getMoney = 0;

                // 更新房间状态
                // if (data.roomUsers) {
                //     GameData.ins.list = data.roomUsers;
                //     GameData.ins.mainNode.emit("onRoomDataChange");
                // }

                // 触发游戏开始事件
                GameData.ins.mainNode.emit("gameStart");
            });
        });

        // 准备倒计时事件
        this.socket.on("ready-countdown", (e) => {
            this.handleSocketEvent("准备倒计时", e, (data) => {
                console.log("准备倒计时:", data.readyCount);
                GameData.ins.rdDownTime = data.readyCount;
                GameData.ins.mainNode.emit("rdDownTime");
            });
        });

        // 游戏倒计时事件
        this.socket.on("game-countdown", (e) => {
            this.handleSocketEvent("游戏倒计时", e, (data) => {
                console.log("游戏倒计时:", data.gameCountdown);
                GameData.ins.downTime = data.gameCountdown;
                GameData.ins.mainNode.emit("downTime");

                const submitScore = () => {
                    if (GameData.ins.getMoney !== GameData.ins.lastSubmittedScore) {
                        SocketManager.ins.socket.emit('submit-score', {
                            roomId: GameData.ins.gameState.roomId,
                            userId: GameData.ins.username,
                            score: GameData.ins.getMoney,
                        });
                        GameData.ins.lastSubmittedScore = GameData.ins.getMoney;
                    }
                };

                if (Math.random() < 0.3 || GameData.ins.downTime === 0) {
                    submitScore();
                }

                if (GameData.ins.downTime === 0) {
                    GameData.ins.isOver = true;
                    GameData.ins.mainNode.emit("gameJs");
                }
            });
        });

        // 更新分数事件
        this.socket.on("score-submitted", (e) => {
            this.handleSocketEvent("更新分数", e, (data) => {
                console.log("游戏分数更新", data);
                if (data) {
                    GameData.ins.getMoney = data.score;
                } else {
                    GameData.ins.getMoney = 0;
                }
                GameData.ins.mainNode.emit("gameDataUpdate");
            });
        });

        // 加入房间事件
        this.socket.on("player-joined", (e) => {
            this.handleSocketEvent("加入房间", e, (data) => {
                // 触发加入房间事件
                if (data.roomId != GameData.ins.roomId) {
                    GameData.ins.list = [];
                }
                // 更新房间数据
                GameData.ins.gameState.ownerId = data.roomInfo.ownerId;
                // GameData.ins.gameState.players = data.gameState.players;
                GameData.ins.gameState.roomId = data.roomInfo.roomId;

                GameData.ins.getRoomUserData(1, Number(GameData.ins.pageInfo.pageSize), "lastActive", "desc", GameData.ins.username);

                GameData.ins.mainNode.emit("onJoinRoom");
                // 触发房间数据变更事件
                GameData.ins.mainNode.emit("onRoomDataChange");

                //上报日志
                // ReportLogs.ins.behaviorReporting("房间操作", "进入房间成功", GameData.ins.gameState.roomId);
            });
        });

        // 游戏结束事件
        this.socket.on("game-finished", (e) => {
            this.handleSocketEvent("游戏结束", e, (data) => {
                // GameData.ins.isOver = true;
                // GameData.ins.mainNode.emit("gameJs");
                // GameData.ins.list = data.roomUsers;
                // GameData.ins.gameState = data.gameState;
                GameData.ins.gameState.roomId = data.roomInfo.roomId;
                GameData.ins.gameState.ownerId = data.roomInfo.ownerId;

                // GameData.ins.getRoomUserData(1, Number(GameData.ins.pageInfo.pageSize), "score", "desc", GameData.ins.username);

                // GameData.ins.mainNode.emit("onRoomDataChange");
                // GameData.ins.getRoomUserData("1");
            });
        });

        // 系统提示
        this.socket.on('tips', (e) => {
            const data = this.decompressData(e);
            if (data) {
                console.log('系统提示:', data.message);
                GameData.ins.mainNode.emit("onTip", data.message || "");
            }
        });

        // 解散房间
        this.socket.on('room-dismissed', (e) => {
            console.log("解散房间");
            this.handleSocketEvent("解散房间", e, (data) => {
                GameData.ins.roomOwnerId = null;
                GameData.ins.list = [];
                GameData.ins.roomId = null;
                GameData.ins.mainNode.emit("onLeaveRoom");
            });
        });

        //获取分页数据
        this.socket.on("paginated-sorted-users", (e) => {
            this.handleSocketEvent("获取分页数据", e, (data) => {
                // 更新房间数据
                GameData.ins.gameState.players = data.pageData.users;
                //更新分页数据
                // GameData.ins.pageInfo = data.pageInfo;
                GameData.ins.pageInfo.total = data.pageData.total;
                //自身数据
                GameData.ins.myInfo.rank = data.pageData.currentUserRank;
                GameData.ins.myInfo.score = data.pageData.currentUserScore;
                // 触发房间数据变更事件
                GameData.ins.mainNode.emit("onRoomDataChange");
            });
        })

        // 错误处理
        this.socket.on('error', (e) => {
            // const data = this.decompressData(e);
            GameData.ins.mainNode.emit("onTip", e || "未知错误");
        });
    }

    public leaveRoom() {
        this.socket.disconnect();
    }

    /**
     * 发送信息
     */
    public sendMessage(name: string = "", data: any) {
        if (!this.socket) return;

        if (data && Object.keys(data).length > 0) {
            const compressedData = this.compressData(data);
            if (compressedData) {
                this.socket.emit(name, compressedData);
            }
        } else {
            this.socket.emit(name, data);
        }
    }

    private handleReconnect() {
        if (this.isConnecting) return;

        if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
            console.error('达到最大重连次数，请检查网络后重试');
            GameData.ins.mainNode.emit("onTip", "网络连接失败，请重新进入游戏");
            return;
        }

        this.isConnecting = true;
        this.reconnectAttempts++;

        if (this.reconnectTimer) {
            clearTimeout(this.reconnectTimer);
        }

        this.reconnectTimer = setTimeout(() => {
            console.log(`第${this.reconnectAttempts}次重连尝试`);
            this.initSocket();
            this.isConnecting = false;
        }, this.RECONNECT_INTERVAL);
    }

    private resetReconnectState() {
        this.reconnectAttempts = 0;
        this.isConnecting = false;
        if (this.reconnectTimer) {
            clearTimeout(this.reconnectTimer);
            this.reconnectTimer = null;
        }
    }

    /**
     * 统一的数据解压处理
     */
    private decompressData(compressedData: any): any {
        try {

            // 使用pako解压缩
            const decompressed = pako.inflate(compressedData, {
                to: 'string'
            });

            return JSON.parse(decompressed);
        } catch (error) {
            console.error('数据解压失败:', error);
            return null;
        }
    }

    /**
     * 统一的数据压缩处理
     */
    private compressData(data: any): Uint8Array {
        try {
            const jsonString = JSON.stringify(data);
            const uint8Array = new TextEncoder().encode(jsonString);
            return pako.deflate(uint8Array);
        } catch (error) {
            console.error('数据压缩失败:', error);
            return null;
        }
    }

    /**
     * 统一的事件处理
     */
    private handleSocketEvent(eventName: string, data: any, handler: (data: any) => void) {
        const decompressedData = this.decompressData(data);
        if (!decompressedData) {
            console.error(`${eventName} 数据解析失败`);
            return;
        }
        console.log(`${eventName} 成功:`, decompressedData);
        handler(decompressedData);
    }
}